package cn.getech.data.metadata.service.impl;

import cn.getech.data.development.entity.TableRelationshipEntity;
import cn.getech.data.development.utils.SendEMailUtil;
import cn.getech.data.metadata.constant.LogTypeEnum;
import cn.getech.data.metadata.entity.*;
import cn.getech.data.metadata.entity.meta.*;
import cn.getech.data.metadata.mapper.BloodRelationshipMapper;
import cn.getech.data.metadata.service.*;
import cn.getech.data.metadata.utils.SendEmailDelayUtil;
import cn.getech.data.metadata.utils.TableHtmlUtil;
import cn.getech.system.center.entity.SysTenant;
import cn.getech.system.center.model.res.UserListRes;
import cn.getech.system.center.service.SysTenantService;
import cn.getech.system.center.service.SysUserService;
import cn.getech.system.center.utils.ShiroUtils;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.math3.util.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.SQLException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.getech.data.development.service.impl.TableInfoServiceImpl.distinctByKey;
import static java.util.stream.Collectors.groupingBy;

@Slf4j
@Service("collectionGenerateService")
public class CollectionGenerateServiceImpl implements CollectionGenerateService {

    @Autowired
    private CollectionTableInfoService collectionTableInfoService;
    @Autowired
    private CollectionTableField2Service collectionTableField2Service;
    @Autowired
    private SysTenantService sysTenantService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private CollectionTableFieldLogService collectionTableFieldLogService;
    @Autowired
    private CollectionTableOperateService collectionTableOperateService;
    @Autowired
    private CollectionTableChangeNotifyService collectionTableChangeNotifyService;
    @Autowired
    private CollectionTableRoleDataPermissionService collectionTableRoleDataPermissionService;
    @Autowired
    private CollectionTableUserNotifyService collectionTableUserNotifyService;
    @Autowired
    private CollectionNotificationRelatednessUserService collectionNotificationRelatednessUserService;
    @Autowired
    private  CollectionNotificationReceivedService collectionNotificationReceivedService;
    @Autowired
    private CollectionNotificationHistoryService collectionNotificationHistoryService;
    @Autowired
    private  CollectionTaskService collectionTaskService;
    @Autowired
    private SendEMailUtil sendEMailUtil;

    @Override
    public void generate(List<CollectionTableInfo> sourceTables, List<CollectionTableInfo> targetTables, Long initRole, Long runUser, Long taskId,
                         Function<String, Long> insertRunLog, Function<CollectionTableInfo, CollectionTableInfo> getRowsAndLength,
                         Consumer<CollectionTableInfo> setTableInfo, Function<CollectionTableInfo, List<CollectionTableField>> getSourceColumns,
                         Function<Integer, List<CollectionTableField>> getTargetTableField, String dbUserName) throws Exception {
        //表分成添加、修改、删除列表
        List<CollectionTableInfo> tableAdds = new ArrayList<>();
        List<CollectionTableInfo> tableUpdates = new ArrayList<>();
        List<CollectionTableInfo> tableDeletes = new ArrayList<>();
        classifyTable(sourceTables, targetTables, tableAdds, tableUpdates, tableDeletes,
                t -> {
                    CollectionTableInfo source = t.getKey();
                    CollectionTableInfo target = t.getValue();
                    return source.getDbName() != null && source.getDbName().equals(target.getDbName()) &&
                            source.getTableName() != null && source.getTableName().equals(target.getTableName()) &&
                            source.getTableType() != null && source.getTableType().equals(target.getTableType());
                }
        );

        //添加表
        List<CollectionTableFieldLog> addTableLogList = new ArrayList<>();
        List<CollectionTableFieldLog> addFieldLogList = new ArrayList<>();
        addTable(taskId,tableAdds, addTableLogList, addFieldLogList, getRowsAndLength,
                setTableInfo, getSourceColumns);

        Set<Integer> changeTableIdSet = new HashSet<>();//表变更通知的表id集合

        //修改表
        List<CollectionTableFieldLog> updateTableLogList = new ArrayList<>();
        List<CollectionTableFieldLog> updateTableAddFieldLogList = new ArrayList<>();
        List<CollectionTableFieldLog> updateTableUpdateFieldLogList = new ArrayList<>();
        List<CollectionTableFieldLog> updateTableDeleteFieldLogList = new ArrayList<>();
        List<CollectionTableFieldLog> noneChangeTableLogList = new ArrayList<>();
        updateTable(sourceTables, tableUpdates, updateTableLogList, updateTableAddFieldLogList, updateTableUpdateFieldLogList,
                updateTableDeleteFieldLogList, changeTableIdSet, noneChangeTableLogList, runUser, getRowsAndLength, getTargetTableField, getSourceColumns);

        //删除表
        List<CollectionTableFieldLog> deleteTableLogList = new ArrayList<>();
        List<CollectionTableFieldLog> deleteFieldLogList = new ArrayList<>();
        if (StringUtils.isEmpty(dbUserName)) {// 元数据注册 需要删除表
            deleteTable(tableDeletes, deleteTableLogList, deleteFieldLogList, changeTableIdSet);
        }
        //添加日志
        addLog(addTableLogList, addFieldLogList,
                updateTableLogList, updateTableAddFieldLogList, updateTableUpdateFieldLogList, updateTableDeleteFieldLogList,
                deleteTableLogList, deleteFieldLogList, noneChangeTableLogList, changeTableIdSet, taskId, runUser, insertRunLog);

        List<CollectionTableInfo> tableAllList = new ArrayList<>();
        tableAllList.addAll(tableAdds);
        tableAllList.addAll(tableUpdates);
        //添加初始化权限
        collectionTableInfoService.saveMetaPermission(tableAllList,initRole,tableDeletes,runUser);
        //添加表关联的数据库用户信息信息
        if (StringUtils.isNotEmpty(dbUserName)) {
            collectionTableInfoService.saveTableDbUsers(tableAdds,tableUpdates,tableDeletes,dbUserName);
        }

    }

    private void addLog(List<CollectionTableFieldLog> addTableLogList, List<CollectionTableFieldLog> addFieldLogList,
                        List<CollectionTableFieldLog> updateTableLogList, List<CollectionTableFieldLog> updateTableAddFieldLogList,
                        List<CollectionTableFieldLog> updateTableUpdateFieldLogList, List<CollectionTableFieldLog> updateTableDeleteFieldLogList,
                        List<CollectionTableFieldLog> deleteTableLogList, List<CollectionTableFieldLog> deleteFieldLogList,
                        List<CollectionTableFieldLog> noneChangeTableLogList, Set<Integer> changeTableIdSet, Long taskId, Long runUser,
                        Function<String, Long> insertRunLog) {
        StringBuilder logContent = new StringBuilder();
        int total = addTableLogList.size() + updateTableLogList.size() + noneChangeTableLogList.size();
        logContent.append("本次成功采集" + total + "张表\n");
        logContent.append("新增" + addTableLogList.size() + "张表\n");
        logContent.append("修改" + updateTableLogList.size() + "张表\n");
        logContent.append("无变化" + noneChangeTableLogList.size() + "张表\n");
        logContent.append("删除" + deleteTableLogList.size() + "张表\n");
        int addFieldCount = addFieldLogList.size() + updateTableAddFieldLogList.size();
        if (addFieldCount > 0)
            logContent.append("新增字段的个数为" + addFieldCount + "\n");
        int updateFieldCount = updateTableUpdateFieldLogList.size();
        if (updateFieldCount > 0)
            logContent.append("修改字段的个数为" + updateFieldCount + "\n");
        int deleteFieldCount = deleteFieldLogList.size() + updateTableDeleteFieldLogList.size();
        if (deleteFieldCount > 0)
            logContent.append("删除字段的个数为" + deleteFieldCount + "\n");
        //添加tasklog、runlog
//        collectionTask.setRunStatus(TaskStatusEnum.SUCCESS.getValue());
//        if(collectionTask.getRunTime() == null)
//            collectionTask.setRunTime(new Date());
//        Long taskLogId = collectionTaskService.insertRunLog(startTime, collectionTask, logContent.toString(), collectionTask.getTaskRunLeader());

        Long taskLogId = insertRunLog.apply(logContent.toString());
        Long userId = runUser;
        //获取所有表字段日志
        List<CollectionTableFieldLog> tableFieldLogList = new ArrayList<>();
        //获取所有表操作
        List<CollectionTableOperateEntity> tableOperateList = new ArrayList<>();
        processAddTableFieldLog(taskLogId, userId, addTableLogList, addFieldLogList, tableFieldLogList, tableOperateList);
        processUpdateTableFieldLog(taskLogId, userId, updateTableLogList, updateTableAddFieldLogList, updateTableUpdateFieldLogList, updateTableDeleteFieldLogList, tableFieldLogList, tableOperateList);
        processDeleteTableFieldLog(taskLogId, userId, deleteTableLogList, deleteFieldLogList, tableFieldLogList, tableOperateList);
        processNoneChangeTableFieldLog(taskLogId, noneChangeTableLogList, tableFieldLogList);
        //表变更通知列表
        List<CollectionTableChangeNotifyEntity> notifyList = getNotifyList(changeTableIdSet, deleteTableLogList, taskLogId, taskId);
        //添加tableFieldLog
        collectionTableFieldLogService.saveTableFieldLog(tableFieldLogList);
        //添加tableOperate
        collectionTableOperateService.saveTableOperate(tableOperateList);
        //添加表变更通知
        saveNotify(notifyList);
        //发送变更信息邮件
        sendEmailFeignApi(tableFieldLogList,taskId,userId);
    }



    private List<CollectionTableChangeNotifyEntity> getNotifyList(Set<Integer> changeTableIdSet, List<CollectionTableFieldLog> deleteTableLogList, Long taskLogId, Long taskId) {
        //表变更通知列表
        List<CollectionTableChangeNotifyEntity> notifyList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(changeTableIdSet)) {
            for (Integer tableId : changeTableIdSet) {
                addNotifyList(tableId, notifyList, taskLogId, taskId);
            }
        }
        if (CollectionUtil.isNotEmpty(deleteTableLogList)) {
            for (CollectionTableFieldLog tableFieldLog : deleteTableLogList) {
                addNotifyList(tableFieldLog.getTableId(), notifyList, taskLogId, taskId);
            }
        }
        return notifyList;
    }

    private void addNotifyList(Integer tableId, List<CollectionTableChangeNotifyEntity> notifyList, Long taskLogId, Long taskId) {
        //判断是否开启变更通知
        boolean isAdd = false;
        int count = collectionTableUserNotifyService.count(
                new QueryWrapper<CollectionTableUserNotifyEntity>()
                        .eq("table_id", tableId)
        );
        if (count > 0)
            isAdd = true;

        if (isAdd) {
            CollectionTableChangeNotifyEntity notifyEntity = new CollectionTableChangeNotifyEntity();
            notifyEntity.setTableId(tableId);
            notifyEntity.setTaskId(taskId);
            notifyEntity.setTaskLogId(taskLogId);
            notifyEntity.setCreateTime(new Date());
            notifyList.add(notifyEntity);
        }
    }

    private void processAddTableFieldLog(Long taskLogId, Long userId, List<CollectionTableFieldLog> addTableLogList, List<CollectionTableFieldLog> addFieldLogList,
                                         List<CollectionTableFieldLog> tableFieldLogList, List<CollectionTableOperateEntity> tableOperateList) {
        if (addTableLogList.size() > 0) {//添加表日志处理
            addTableLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);

                CollectionTableOperateEntity operateEntity = new CollectionTableOperateEntity();
                operateEntity.setTableId(log.getTableId());
                operateEntity.setOperateType(1); //1:表结构 2:表属性
                operateEntity.setOperateType1Res(taskLogId);
                operateEntity.setOperateType2Res("");
                operateEntity.setUserId(userId);
                operateEntity.setOperateTime(new Date());
                if (!tableOperateList.contains(operateEntity))
                    tableOperateList.add(operateEntity);
            });
            tableFieldLogList.addAll(addTableLogList);

            addFieldLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);
            });
            tableFieldLogList.addAll(addFieldLogList);
        }
    }

    private void processUpdateTableFieldLog(Long taskLogId, Long userId, List<CollectionTableFieldLog> updateTableLogList, List<CollectionTableFieldLog> updateTableAddFieldLogList,
                                            List<CollectionTableFieldLog> updateTableUpdateFieldLogList, List<CollectionTableFieldLog> updateTableDeleteFieldLogList,
                                            List<CollectionTableFieldLog> tableFieldLogList, List<CollectionTableOperateEntity> tableOperateList) {
        if (updateTableLogList.size() > 0) {//修改表日志处理
            updateTableLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);

                CollectionTableOperateEntity operateEntity = new CollectionTableOperateEntity();
                operateEntity.setTableId(log.getTableId());
                operateEntity.setOperateType(1); //1:表结构 2:表属性
                operateEntity.setOperateType1Res(taskLogId);
                operateEntity.setOperateType2Res("");
                operateEntity.setUserId(userId);
                operateEntity.setOperateTime(new Date());
                if (!tableOperateList.contains(operateEntity))
                    tableOperateList.add(operateEntity);
            });
            tableFieldLogList.addAll(updateTableLogList);

            updateTableAddFieldLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);
            });
            tableFieldLogList.addAll(updateTableAddFieldLogList);

            updateTableUpdateFieldLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);
            });
            tableFieldLogList.addAll(updateTableUpdateFieldLogList);

            updateTableDeleteFieldLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);
            });
            tableFieldLogList.addAll(updateTableDeleteFieldLogList);
        }
    }

    private void processDeleteTableFieldLog(Long taskLogId, Long userId, List<CollectionTableFieldLog> deleteTableLogList, List<CollectionTableFieldLog> deleteFieldLogList,
                                            List<CollectionTableFieldLog> tableFieldLogList, List<CollectionTableOperateEntity> tableOperateList) {
        if (deleteTableLogList.size() > 0) {//删除表日志处理
            deleteTableLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);

                CollectionTableOperateEntity operateEntity = new CollectionTableOperateEntity();
                operateEntity.setTableId(log.getTableId());
                operateEntity.setOperateType(1); //1:表结构 2:表属性
                operateEntity.setOperateType1Res(taskLogId);
                operateEntity.setOperateType2Res("");
                operateEntity.setUserId(userId);
                operateEntity.setOperateTime(new Date());
                if (!tableOperateList.contains(operateEntity))
                    tableOperateList.add(operateEntity);
            });
            tableFieldLogList.addAll(deleteTableLogList);

            deleteFieldLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);
            });
            tableFieldLogList.addAll(deleteFieldLogList);
        }
    }

    private void processNoneChangeTableFieldLog(Long taskLogId, List<CollectionTableFieldLog> noneChangeTableLogList,
                                                List<CollectionTableFieldLog> tableFieldLogList) {
        if (noneChangeTableLogList.size() > 0) {//删除表日志处理
            noneChangeTableLogList.stream().forEach(log -> {
                log.setLogId(taskLogId);
            });
            tableFieldLogList.addAll(noneChangeTableLogList);
        }
    }

    private void saveNotify(List<CollectionTableChangeNotifyEntity> notifyList) {
        if (notifyList.size() > 0) {
            int start = 0, limit = 200;
            List<CollectionTableChangeNotifyEntity> collect = notifyList.stream().skip(start).limit(limit).collect(Collectors.toList());
            while (collect != null && collect.size() > 0) {
                collectionTableChangeNotifyService.saveBatch(collect);

                start += limit;
                collect = notifyList.stream().skip(start).limit(limit).collect(Collectors.toList());
            }
        }
    }

    private void addTable(Long taskId,List<CollectionTableInfo> tableAdds, List<CollectionTableFieldLog> addTableLogList,
                          List<CollectionTableFieldLog> addFieldLogList,
                          Function<CollectionTableInfo, CollectionTableInfo> getRowsAndLength, Consumer<CollectionTableInfo> setTableInfo,
                          Function<CollectionTableInfo, List<CollectionTableField>> getSourceColumns) throws SQLException {
        if (tableAdds != null && tableAdds.size() > 0) {
            for (CollectionTableInfo tableInfo : tableAdds) {
                CollectionTableInfo addRowsAndLength = getRowsAndLength.apply(tableInfo);
                if (addRowsAndLength != null) {
                    tableInfo.setRowsNum(addRowsAndLength.getRowsNum());
                    tableInfo.setTotalSize(addRowsAndLength.getTotalSize());
                } else {
                    tableInfo.setRowsNum(0L);
                    tableInfo.setTotalSize(0.0);
                }
                List<CollectionTableField> sourceFieldList = null;
                try {
                    sourceFieldList = getSourceColumns.apply(tableInfo);
                } catch (Exception e) {
                    log.error("获取字段信息错误",e);
                }
                if (CollectionUtil.isNotEmpty(sourceFieldList)) {
                    addTableInfo(taskId,tableInfo, addTableLogList,setTableInfo);
                    addTableFields(tableInfo, sourceFieldList, addFieldLogList);
                }
            }
        }
    }

    private void updateTable(List<CollectionTableInfo> sourceTables, List<CollectionTableInfo> tableUpdates, List<CollectionTableFieldLog> updateTableLogList,
                             List<CollectionTableFieldLog> addFieldLogList, List<CollectionTableFieldLog> updateTableUpdateFieldLogList,
                             List<CollectionTableFieldLog> updateTableDeleteFieldLogList, Set<Integer> changeTableIdSet, List<CollectionTableFieldLog> noneChangeTableLogList,
                             Long runUser, Function<CollectionTableInfo, CollectionTableInfo> getRowsAndLength, Function<Integer, List<CollectionTableField>> getTargetTableField,
                             Function<CollectionTableInfo, List<CollectionTableField>> getSourceColumns) throws SQLException {
        if (tableUpdates != null && tableUpdates.size() > 0) {
            for (CollectionTableInfo tableInfo : tableUpdates) {
                CollectionTableInfo sourceTable = sourceTables.stream().filter(s -> s.getTableName().equals(tableInfo.getTableName())).findFirst().get();
                List<CollectionTableField> sourceFields = null;
                try {
                    sourceFields = getSourceColumns.apply(tableInfo);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
                List<CollectionTableField> targetFields = getTargetTableField.apply(tableInfo.getId());
                List<CollectionTableField> fieldAdds = new ArrayList<>();
                List<CollectionTableField> fieldUpdates = new ArrayList<>();
                List<CollectionTableField> fieldDeletes = new ArrayList<>();
                classifyTable(sourceFields, targetFields, fieldAdds, fieldUpdates, fieldDeletes,
                        t -> {
                            CollectionTableField source = t.getKey();
                            CollectionTableField target = t.getValue();
                            return source.getFieldName() != null && source.getFieldName().equals(target.getFieldName());
                        }
                );

                addTableFields(tableInfo, fieldAdds, addFieldLogList);

                boolean isChange = updateTableFields(fieldUpdates, sourceFields, updateTableUpdateFieldLogList);

                deleteTableFields(fieldDeletes, updateTableDeleteFieldLogList);

                boolean isUpdate = fieldAdds.size() > 0 || isChange || fieldDeletes.size() > 0;
                CollectionTableInfo updateRowsAndLength = getRowsAndLength.apply(sourceTable);
                updateTableInfo(sourceTable, tableInfo, updateRowsAndLength, isUpdate, updateTableLogList, runUser);
                if (!isUpdate) {
                    CollectionTableFieldLog tableFieldLog = new CollectionTableFieldLog();
                    tableFieldLog.setTableId(tableInfo.getId());
                    tableFieldLog.setFieldId(0);
                    tableFieldLog.setLogType(LogTypeEnum.NONE.getValue());
                    tableFieldLog.setDataType(0);//0 表 1 字段
                    noneChangeTableLogList.add(tableFieldLog);
                } else
                    changeTableIdSet.add(tableInfo.getId());//添加表变更通知
            }
        }
    }

    /**
     * 给表列表或者表字段列表分类
     *
     * @param sourceTables 源表列表或者字段列表
     * @param targetTables 目的表列表或者字段列表
     * @param tableAdds    新添加的表或者字段
     * @param tableUpdates 更新的表或者字段
     * @param tableDeletes 删除的表或者字段
     */
    private <T> void classifyTable(List<T> sourceTables, List<T> targetTables,
                                   List<T> tableAdds, List<T> tableUpdates, List<T> tableDeletes, Function<Pair<T, T>, Boolean> func) {
        if (sourceTables == null)
            sourceTables = new ArrayList<T>();
        if (targetTables == null)
            targetTables = new ArrayList<>();

        if (sourceTables.size() > 0) {
            for (T tableInfo : sourceTables) {
                Optional<T> first = targetTables.stream()
                        .filter(t -> func.apply(Pair.create(tableInfo, t))).findFirst();
                if (!first.isPresent()) {//没查到有改表是新增的表
                    tableAdds.add(tableInfo);
                } else {//有查到的表放到更新表里面验证
                    tableUpdates.add(first.get());
                    targetTables.remove(first.get());//目标表列表删除表
                }
            }
        }

        if (targetTables.size() > 0) {//目标表列表还有数据是删除的表
            tableDeletes.addAll(targetTables);
        }
    }

    private void processPermission(List<CollectionRoleDataPermission> addPermissionList, List<CollectionRoleDataPermission> deletePermissionList) {
        if (CollectionUtil.isNotEmpty(addPermissionList)) {
            saveDataPermission(addPermissionList);
        }

        if (CollectionUtil.isNotEmpty(deletePermissionList)) {
            deleteDataPermission(deletePermissionList);
        }
    }

    private void saveDataPermission(List<CollectionRoleDataPermission> addPermissionList) {
        if (addPermissionList.size() > 0) {
            int start = 0, limit = 200;
            List<CollectionRoleDataPermission> collect = addPermissionList.stream().skip(start).limit(limit).collect(Collectors.toList());
            while (collect.size() > 0) {
                List<CollectionRoleDataPermission> collect2 = new ArrayList<>();
                for (CollectionRoleDataPermission dataPermission : collect) {
                    QueryWrapper<CollectionRoleDataPermission> param = new QueryWrapper<CollectionRoleDataPermission>()
                            .eq("role_id", dataPermission.getRoleId())
                            .eq("data_id", dataPermission.getDataId())
                            .eq("data_type", dataPermission.getDataType());
                    int count = collectionTableRoleDataPermissionService.count(param);
                    if (count == 0) {
                        collect2.add(dataPermission);
                    } else {
                        collectionTableRoleDataPermissionService.update(dataPermission, param);
                    }
                }
                collectionTableRoleDataPermissionService.saveBatch(collect2);
                start += limit;
                collect = addPermissionList.stream().skip(start).limit(limit).collect(Collectors.toList());
            }
        }
    }

    private void deleteDataPermission(List<CollectionRoleDataPermission> deletePermissionList) {
        if (deletePermissionList.size() > 0) {
            int start = 0, limit = 200;
            List<Integer> collect = deletePermissionList.stream().skip(start).limit(limit)
                    .map(CollectionRoleDataPermission::getId).collect(Collectors.toList());
            while (collect.size() > 0) {
                collectionTableRoleDataPermissionService.removeByIds(collect);
                start += limit;
                collect = deletePermissionList.stream().skip(start).limit(limit)
                        .map(CollectionRoleDataPermission::getId).collect(Collectors.toList());
            }
        }
    }

    private void addTableInfo(Long taskId,CollectionTableInfo tableInfo, List<CollectionTableFieldLog> addTableLogList,

                              Consumer<CollectionTableInfo> setTableInfo) {
        setTableInfo.accept(tableInfo);
        collectionTableInfoService.save(tableInfo);
        //建立表和目录之间的关系
        collectionTableInfoService.saveCollectionTableCategory(tableInfo.getId(),taskId, ShiroUtils.getTenantId(),ShiroUtils.getUserId().intValue());
        //添加表日志
        CollectionTableFieldLog tableLog = new CollectionTableFieldLog();
        tableLog.setTableId(tableInfo.getId());
        tableLog.setFieldId(0);
        tableLog.setDataType(0);//0 表 1 字段
        tableLog.setLogType(LogTypeEnum.ADD.getValue());
        addTableLogList.add(tableLog);
    }

    private void updateTableInfo(CollectionTableInfo sourceTable, CollectionTableInfo tableInfo, CollectionTableInfo updateRowsAndLength, boolean isUpdate,
                                 List<CollectionTableFieldLog> updateTableLogList, Long runUser) {
        if (isUpdate) {
            //添加表日志
            CollectionTableFieldLog tableLog = new CollectionTableFieldLog();
            tableLog.setTableId(tableInfo.getId());
            tableLog.setFieldId(0);
            tableLog.setDataType(0);//0 表 1 字段
            tableLog.setLogType(LogTypeEnum.UPDATE.getValue());
            updateTableLogList.add(tableLog);
        }

        CollectionTableInfo updateTable = new CollectionTableInfo();
        updateTable.setOwnSystem(sourceTable.getOwnSystem());
        updateTable.setOwnModule(sourceTable.getOwnModule());
        updateTable.setRowsNum(tableInfo.getRowsNum());
        updateTable.setTotalSize(tableInfo.getTotalSize());
        updateTable.setId(tableInfo.getId());
        if (updateRowsAndLength != null) {
            if (updateRowsAndLength.getRowsNum() == null)
                updateRowsAndLength.setRowsNum(0L);
            if (updateRowsAndLength.getTotalSize() == null)
                updateRowsAndLength.setTotalSize(0.0);

            if (tableInfo.getRowsNum().longValue() != updateRowsAndLength.getRowsNum().longValue()) {
                updateTable.setRowsNum(updateRowsAndLength.getRowsNum());
            }
            if (tableInfo.getTotalSize().longValue() != updateRowsAndLength.getTotalSize().longValue()) {
                updateTable.setTotalSize(updateRowsAndLength.getTotalSize());
            }
        }

        if (StringUtils.isNotEmpty(sourceTable.getTableAlias())) {
            if (!sourceTable.getTableAlias().equals(tableInfo.getTableAlias())) {
                updateTable.setTableDesc(sourceTable.getTableDesc());
                updateTable.setTableAlias(sourceTable.getTableAlias());
            }
        }
        updateTable.setUpdateTime(new Date());
        updateTable.setUpdateUser(runUser);
        updateTable.setUpdateTableTime(new Date());
        collectionTableInfoService.updateById(updateTable);
    }

    private void deleteTable(List<CollectionTableInfo> tableDeletes, List<CollectionTableFieldLog> deleteTableLogList,
                             List<CollectionTableFieldLog> deleteFieldLogList, Set<Integer> changeTableIdSet) throws SQLException {
        if (tableDeletes != null && tableDeletes.size() > 0) {
            for (CollectionTableInfo tableInfo : tableDeletes) {
                //添加表日志
                CollectionTableFieldLog tableLog = new CollectionTableFieldLog();
                tableLog.setTableId(tableInfo.getId());
                tableLog.setFieldId(0);
                tableLog.setDataType(0);//0 表 1 字段
                tableLog.setLogType(LogTypeEnum.DELETE.getValue());
                deleteTableLogList.add(tableLog);
                changeTableIdSet.add(tableInfo.getId());//添加表变更通知

                List<CollectionTableField> fieldDeletes = collectionTableField2Service.list(
                        new QueryWrapper<CollectionTableField>()
                                .eq("table_id", tableInfo.getId())
                                .eq("delete_flag", 0)
                );

                deleteTableFields(fieldDeletes, deleteFieldLogList);

                int count = collectionTableInfoService.count(
                        new QueryWrapper<CollectionTableInfo>()
                                .eq("db_name", tableInfo.getDbName())
                                .eq("table_name", tableInfo.getTableName())
                                .eq("own_module", tableInfo.getOwnModule())
                                .gt("delete_flag", 0)
                );
                CollectionTableInfo deleteTable = new CollectionTableInfo();
                deleteTable.setId(tableInfo.getId());
                deleteTable.setDeleteFlag(count + 1);
                collectionTableInfoService.updateById(deleteTable);
            }
        }
    }

    private void addTableFields(CollectionTableInfo tableInfo, List<CollectionTableField> fieldList, List<CollectionTableFieldLog> addFieldLogList) {
        if (fieldList != null && fieldList.size() > 0) {
            for (CollectionTableField tableField : fieldList) {
                tableField.setTableId(tableInfo.getId());
                if (tableField.getIsPartition() == null) {
                    tableField.setIsPartition(0);//是否是分区字段 1 是,0 否
                }
                //设置字段默认数据密级，因为表中的默认数据密级在前面设置了，所以这里可以直接从表信息中获取
                tableField.setSecurityDataLevel(tableInfo.getSecurityDataLevel());
                tableField.setCreateTime(new Date());
                tableField.setCreateUser(0L);
                tableField.setUpdateTime(tableInfo.getCreateTime());
                tableField.setUpdateUser(tableInfo.getCreateUser());
                tableField.setDeleteFlag(0);//删除 1 是,0 否
                try {
                    collectionTableField2Service.save(tableField);
                } catch (Exception e) {
                   log.warn("表名{},字段名添{},加失败,{}",tableInfo.getTableName(),tableField.getFieldName(),e.getMessage());
                }
                //添加字段日志
                CollectionTableFieldLog fieldLog = new CollectionTableFieldLog();
                fieldLog.setTableId(tableField.getTableId());
                fieldLog.setFieldId(tableField.getId());
                fieldLog.setDataType(1);//0 表 1 字段
                fieldLog.setLogType(LogTypeEnum.ADD.getValue());
                addFieldLogList.add(fieldLog);
            }
        }
    }

    private boolean updateTableFields(List<CollectionTableField> fieldUpdates, List<CollectionTableField> sourceFields, List<CollectionTableFieldLog> updateTableLogList) throws SQLException {
        List<CollectionTableField> updateList = new ArrayList<>();
        if (fieldUpdates != null && fieldUpdates.size() > 0) {
            for (CollectionTableField tableField : fieldUpdates) {
                CollectionTableField sourceField = sourceFields.stream().filter(f -> f.getFieldName().equals(tableField.getFieldName())).findFirst().get();

                boolean isUpdate = false;
                //字段类型更新逻辑判断
                String changeInfo = "";
                if (!sourceField.getFieldType().equals(tableField.getFieldType())) {
                    changeInfo = String.format("字段类型 %s -> %s ", tableField.getFieldType(), sourceField.getFieldType());
                    tableField.setFieldType(sourceField.getFieldType());
                    isUpdate = true;
                }

                //主键字段更新移动到下面判断
               /* if (sourceField.getPrimaryKey()!=null && !sourceField.getPrimaryKey().equals(tableField.getPrimaryKey())) {
                    changeInfo += String.format("是否主键 %s -> %s", tableField.getPrimaryKey()==1?"是":"否",
                            sourceField.getPrimaryKey()==1?"是":"否");
                    tableField.setPrimaryKey(sourceField.getPrimaryKey());
                    isUpdate = true;
                }*/

                //字段描述更新判断
                if (sourceField.getFieldDesc() != null || tableField.getFieldDesc() != null) {
                    String sourceDesc = null;
                    String descDesc = null;
                    if (sourceField.getFieldDesc() != null) {
                        sourceDesc = sourceField.getFieldDesc();
                        descDesc = tableField.getFieldDesc();
                    } else if (tableField.getFieldDesc() != null) {
                        sourceDesc = tableField.getFieldDesc();
                        descDesc = sourceField.getFieldDesc();
                    }

                    if (!sourceDesc.equals(descDesc)) {
                        changeInfo += String.format("字段描述 %s -> %s", tableField.getFieldDesc(), sourceField.getFieldDesc());
                        tableField.setFieldDesc(sourceField.getFieldDesc());
                        isUpdate = true;
                    }
                }
                //分区字段更新逻辑判断
                //分区字段标识没值的，设置默认值否
                if(sourceField.getIsPartition()==null){
                    sourceField.setIsPartition(0);
                }
                if(tableField.getIsPartition()==null){
                    tableField.setIsPartition(0);
                }
                if (sourceField.getIsPartition() != null && tableField.getIsPartition() != null) {
                    Integer sourceIsPartition = sourceField.getIsPartition();
                    Integer descIsPartition = tableField.getIsPartition();
                    if (!sourceIsPartition.equals(descIsPartition)) {
                        changeInfo += String.format("是否分区 %s -> %s", tableField.getIsPartition()==1?"是":"否", sourceField.getIsPartition()==1?"是":"否");
                        tableField.setIsPartition(sourceField.getIsPartition());
                        isUpdate = true;
                    }
                }
                //是否为空更新逻辑判断
                // 是否为空标识没值的，设置默认值否
                if(sourceField.getFieldIsNull()==null){
                    sourceField.setFieldIsNull(0);
                }
                if(tableField.getFieldIsNull()==null){
                    tableField.setFieldIsNull(0);
                }
                if (sourceField.getFieldIsNull() != null && tableField.getFieldIsNull() != null) {
                    Integer sourceIsNull = sourceField.getFieldIsNull();
                    Integer descIsNull = tableField.getFieldIsNull();
                    if (!sourceIsNull.equals(descIsNull)) {
                        changeInfo += String.format("是否为空 %s -> %s", tableField.getFieldIsNull()==1?"是":"否", sourceField.getFieldIsNull()==1?"是":"否");
                        tableField.setFieldIsNull(sourceField.getFieldIsNull());
                        isUpdate = true;
                    }
                }

                //字段长度更新逻辑判断
                if(sourceField.getFieldLength()==null){
                    sourceField.setFieldLength(0);
                }
                if(tableField.getFieldLength()==null){
                    tableField.setFieldLength(0);
                }
                if (sourceField.getFieldLength() != null && tableField.getFieldLength() != null) {
                    Integer sourceLength = sourceField.getFieldLength();
                    Integer descLength= tableField.getFieldLength();
                    if (!sourceLength.equals(descLength)) {
                        changeInfo += String.format("字段长度 %s -> %s", tableField.getFieldLength(), sourceField.getFieldLength());
                        tableField.setFieldLength(sourceField.getFieldLength());
                        isUpdate = true;
                    }
                }
                //主键更新逻辑判断
                // 主键字段标识没值的，设置默认值否
                if(sourceField.getPrimaryKey()==null){
                    sourceField.setPrimaryKey(0);
                }
                if(tableField.getPrimaryKey()==null){
                    tableField.setPrimaryKey(0);
                }
                if (sourceField.getPrimaryKey() != null && tableField.getPrimaryKey() != null) {
                    Integer sourceIsPrimaryKey = sourceField.getPrimaryKey();
                    Integer descIsPrimaryKey = tableField.getPrimaryKey();
                    if (!sourceIsPrimaryKey.equals(descIsPrimaryKey)) {
                        changeInfo += String.format("是否主键 %s -> %s", tableField.getPrimaryKey()==1?"是":"否", sourceField.getPrimaryKey()==1?"是":"否");
                        tableField.setPrimaryKey(sourceField.getPrimaryKey());
                        isUpdate = true;
                    }
                }
                if (isUpdate) {
                    //添加字段日志
                    CollectionTableFieldLog fieldLog = new CollectionTableFieldLog();
                    fieldLog.setTableId(tableField.getTableId());
                    fieldLog.setFieldId(tableField.getId());
                    fieldLog.setDataType(1);//0 表 1 字段
                    fieldLog.setLogType(LogTypeEnum.UPDATE.getValue());
                    String changeInfoNew = sourceField.getFieldName() + "(" + changeInfo + ")";
                    fieldLog.setChangeInfo(changeInfoNew);
                    updateTableLogList.add(fieldLog);

                    tableField.setUpdateTime(new Date());
                    updateList.add(tableField);
                }
            }

            if (updateList.size() > 0) {
                collectionTableField2Service.updateBatchById(updateList);
            }
        }

        return updateList.size() > 0;
    }
    @Autowired
    private BloodRelationshipMapper bloodRelationshipMapper;
    private void deleteTableFields(List<CollectionTableField> fieldDeletes, List<CollectionTableFieldLog> deleteFieldLogList) {
        if (fieldDeletes != null && fieldDeletes.size() > 0) {
            Map<Integer, List<CollectionTableField>> fieldDeletesMap = fieldDeletes.stream().filter(s ->
                     s.getTableId()!=null).collect(Collectors.groupingBy(CollectionTableField::getTableId));
            for (Integer tableId : fieldDeletesMap.keySet()) {
                List<String> fieldNames = fieldDeletesMap.get(tableId).stream()
                        .map(CollectionTableField::getFieldName).collect(Collectors.toList());
                for (CollectionTableField tableField : fieldDeletesMap.get(tableId)) {
                    //添加字段日志
                    CollectionTableFieldLog fieldLog = new CollectionTableFieldLog();
                    fieldLog.setTableId(tableField.getTableId());
                    fieldLog.setFieldId(tableField.getId());
                    fieldLog.setDataType(1);//0 表 1 字段
                    fieldLog.setLogType(LogTypeEnum.DELETE.getValue());
                    deleteFieldLogList.add(fieldLog);
                    tableField.setDeleteFlag(1);
                }
                collectionTableField2Service.updateBatchById(fieldDeletesMap.get(tableId));
                try {
                    bloodRelationshipMapper.delete(
                            new QueryWrapper<TableRelationshipEntity>()
                                    .eq("source_coll_table_id",
                                            tableId)
                                    .in("source_field_name",fieldNames));
                    bloodRelationshipMapper.delete(
                            new QueryWrapper<TableRelationshipEntity>()
                                    .eq("relation_coll_table_id",tableId)
                                    .in("relation_field_name",fieldNames));
                } catch (Exception e) {
                    log.warn("删除血缘异常:{}",e.getMessage());
                }
            }
        }
    }

    /**
     * 发送元数据采集详情的邮件
     * @param tableFieldLogList
     * @param taskId
     * @param userId
     */
    private void sendEmailFeignApi(List<CollectionTableFieldLog> tableFieldLogList, Long taskId, Long userId) {
        if(CollectionUtil.isNotEmpty(tableFieldLogList)){
            //添加字段
            ArrayList<CollectionNotificationExample> addField=new ArrayList<CollectionNotificationExample>();
            //修改字段
            ArrayList<CollectionNotificationExample> updateField=new ArrayList<CollectionNotificationExample>();
            //删除字段
            ArrayList<CollectionNotificationExample> delField=new ArrayList<CollectionNotificationExample>();
            //更新表
            ArrayList<CollectionNotificationExample> updateTable=new ArrayList<CollectionNotificationExample>();
            //删除表
            ArrayList<CollectionNotificationExample> delTable=new ArrayList<CollectionNotificationExample>();
            //依照类型进行分组  增删查改
            Map<Integer, List<CollectionTableFieldLog>> collect = tableFieldLogList.stream().collect(groupingBy(CollectionTableFieldLog::getLogType));
            if(CollectionUtil.isNotEmpty(collect)){
                for (Integer key : collect.keySet()){
                    //新增
                    if(key==0){
                        List<CollectionTableFieldLog> collectionTableFieldLogs = collect.get(key);
                        for(CollectionTableFieldLog collectionTableFieldLog:collectionTableFieldLogs){
                             //表
                            if(collectionTableFieldLog.getDataType()==0){
                            }else {
                                CollectionNotificationExample collectionNotificationExample=new CollectionNotificationExample();
                                CollectionTableField byId = collectionTableField2Service.getById(collectionTableFieldLog.getFieldId());
                                CollectionTableInfo byId1 = collectionTableInfoService.getById(byId.getTableId());
                                BeanUtils.copyProperties(byId1,collectionNotificationExample);
                                collectionNotificationExample.setChangeContent(byId.getFieldName()+"  ("+byId.getFieldType()+")");
                                collectionNotificationExample.setChangeType("新增字段");
                                addField.add(collectionNotificationExample);
                            }
                        }
                    }
                    //修改
                    if(key==1){
                        List<CollectionTableFieldLog> collectionTableFieldLogs = collect.get(key);
                        for(CollectionTableFieldLog collectionTableFieldLog:collectionTableFieldLogs){
                            //表  有修改字段和添加字段
                            if(collectionTableFieldLog.getDataType()==0){
                            //字段
                            }else {
                                CollectionNotificationExample collectionNotificationExample=new CollectionNotificationExample();
                                CollectionTableField byId = collectionTableField2Service.getById(collectionTableFieldLog.getFieldId());
                                CollectionTableInfo byId1 = collectionTableInfoService.getById(byId.getTableId());
                                BeanUtils.copyProperties(byId1,collectionNotificationExample);
                                collectionNotificationExample.setChangeContent(collectionTableFieldLog.getChangeInfo());
                                collectionNotificationExample.setChangeType("修改字段类型");
                                updateField.add(collectionNotificationExample);
                            }
                        }
                    }
                    //删除
                    if(key==2){
                        List<CollectionTableFieldLog> collectionTableFieldLogs = collect.get(key);
                        for(CollectionTableFieldLog collectionTableFieldLog:collectionTableFieldLogs){
                            //表
                            if(collectionTableFieldLog.getDataType()==0){
                                CollectionNotificationExample collectionNotificationExample=new CollectionNotificationExample();
                                CollectionTableInfo byId1 = collectionTableInfoService.getById(collectionTableFieldLog.getTableId());
                                BeanUtils.copyProperties(byId1,collectionNotificationExample);
                                collectionNotificationExample.setChangeContent(byId1.getTableName());
                                collectionNotificationExample.setChangeType("删除表");
                                delTable.add(collectionNotificationExample);
                            }else {
                                CollectionNotificationExample collectionNotificationExample=new CollectionNotificationExample();
                                //字段
                                CollectionTableField byId = collectionTableField2Service.getById(collectionTableFieldLog.getFieldId());
                                //表
                                CollectionTableInfo byId1 = collectionTableInfoService.getById(byId.getTableId());
                                BeanUtils.copyProperties(byId1,collectionNotificationExample);
                                collectionNotificationExample.setChangeContent(byId.getFieldName());
                                collectionNotificationExample.setChangeType("删除字段");
                                delField.add(collectionNotificationExample);
                            }
                        }
                    }
                }
            }
            //拼接邮件其他的参数并当历史数据保存
            CollectionTask byId = collectionTaskService.getById(taskId);
            UserListRes info = sysUserService.info(byId.getCreateUser());
            //查询租户信息
            SysTenant byId1 = sysTenantService.getById(byId.getTenantId());
            //拼接所有的邮箱
            StringBuffer email = new StringBuffer();
            HashMap<String,String> map = new HashMap<>();
            map.put("title",byId.getTaskName());
            map.put("taskName",byId.getTaskName());
            map.put("creatuser",info.getUsername()+"("+byId1.getName()+")");
            map.put("toemail",info.getEmail());
            //查询（多个用户组）
            List<CollectionNotificationUser> collectionNotificationUsers = collectionNotificationRelatednessUserService.queryNotificaCondition(taskId, "1");
            if(CollectionUtil.isNotEmpty(collectionNotificationUsers)){
                 //循环用户组获取所有的发送邮箱
                for(CollectionNotificationUser collectionNotificationUser:collectionNotificationUsers){
                    //获取要发送的邮箱信息
                    List<CollectionNotificationReceived> collectionNotificationReceiveds = collectionNotificationReceivedService.queryByNotificationUserId(collectionNotificationUser.getId());
                    //免打扰结束时间为空，或当前时间免大于免打扰结束时间，或者当前时间小于免打扰开始时间，都立刻发
                    if (collectionNotificationUser.getNoDisturbingEnd() == null ||
                            (collectionNotificationUser.getNoDisturbingEnd()!=null&& LocalTime.now().compareTo(UDateToLocalTime(collectionNotificationUser.getNoDisturbingEnd()))>0) ||
                            (collectionNotificationUser.getNoDisturbingStart()!=null&& LocalTime.now().compareTo(UDateToLocalTime(collectionNotificationUser.getNoDisturbingStart()))<0) ){
                        //判断为空
                        if(CollectionUtil.isNotEmpty(collectionNotificationReceiveds)){
                            //对发送的邮箱进行去重操作
                            List<CollectionNotificationReceived> personList = new ArrayList<>();
                            collectionNotificationReceiveds.stream().filter(distinctByKey(p -> p.getEmail())).forEach(p -> personList.add(p));
                            //对告警接收人统一发送
                            for(CollectionNotificationReceived notificationReceived:personList){
                                email.append(notificationReceived.getEmail()+",");
                            }
                            map.put("email",email.toString());
                            //发送邮件(已经去重了)
                            for(CollectionNotificationReceived collectionNotificationReceived:personList){
                                try {
                                    StringBuilder stringBuilder = TableHtmlUtil.tableToHTML(addField, updateField, delField, updateTable, delTable, map);
                                    if(stringBuilder==null){ return;}
                                    //发送邮件
                                    String content = stringBuilder.toString();
                                    sendEMailUtil.createSimpleMail(collectionNotificationReceived.getEmail(),map.get("title")+"的源端元数据变更通知",content);
                                    //保存历史记录
                                    CollectionNotificationHistory collectionNotificationHistory = new CollectionNotificationHistory();
                                    BeanUtils.copyProperties(collectionNotificationReceived,collectionNotificationHistory);
                                    collectionNotificationHistory.setCreateTime(new Date());
                                    collectionNotificationHistory.setNotificationContent(content);
                                    collectionNotificationHistory.setNotificationTitle(map.get("title")+"的源端元数据变更通知");
                                    collectionNotificationHistory.setNotificationTime(new Date());
                                    collectionNotificationHistory.setNotificationFlag(1);
                                    collectionNotificationHistory.setRelatednessType("1");
                                    collectionNotificationHistory.setNotificationType("1");
                                    collectionNotificationHistory.setTenantId(collectionNotificationReceived.getTenantId());
                                    collectionNotificationHistory.setCreateUser(collectionNotificationReceived.getCreateUser());
                                    collectionNotificationHistory.setNotificationReceivedId(byId.getId());
                                    collectionNotificationHistoryService.saveCollectionNotificationHistory(collectionNotificationHistory);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }else{
                        if(CollectionUtil.isNotEmpty(collectionNotificationReceiveds)){
                            //对发送的邮箱进行去重操作
                            List<CollectionNotificationReceived> personList = new ArrayList<>();
                            collectionNotificationReceiveds.stream().filter(distinctByKey(p -> p.getEmail())).forEach(p -> personList.add(p));
                            for(CollectionNotificationReceived notificationReceived:personList){
                                email.append(notificationReceived.getEmail()+",");
                            }
                            map.put("email",email.toString());
                            //发送邮件(已经去重了)
                            for(CollectionNotificationReceived collectionNotificationReceived:personList){
                                StringBuilder stringBuilder = TableHtmlUtil.tableToHTML(addField, updateField, delField, updateTable, delTable, map);
                                if(stringBuilder==null){ return; }
                                //保存信息
                                String content = stringBuilder.toString();
                                CollectionNotificationHistory collectionNotificationHistory = new CollectionNotificationHistory();
                                BeanUtils.copyProperties(collectionNotificationReceived,collectionNotificationHistory);
                                collectionNotificationHistory.setCreateTime(new Date());
                                collectionNotificationHistory.setNotificationContent(content);
                                collectionNotificationHistory.setNotificationTitle("元数据自动采集变更通知");
                                collectionNotificationHistory.setNotificationTime(new Date());
                                collectionNotificationHistory.setNotificationReceivedId(byId.getId());
                                collectionNotificationHistory.setNotificationFlag(2);
                                collectionNotificationHistory.setTenantId(collectionNotificationReceived.getTenantId());
                                collectionNotificationHistory.setCreateUser(collectionNotificationReceived.getCreateUser());
                                collectionNotificationHistory.setRelatednessType("1");
                                collectionNotificationHistory.setNotificationType("1");
                                collectionNotificationHistoryService.saveCollectionNotificationHistory(collectionNotificationHistory);
                            }
                            //添加任务
                            SendEmailDelayUtil.addTask(collectionNotificationUser.getId(), collectionNotificationUser.getNoDisturbingEnd().getTime(),"");
                        }
                    }
                }
            }
         }
    }

    /**
     *  data 转 LocalTime
     * @param date
     * @return
     */
    public LocalTime UDateToLocalTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
        LocalTime localTime = localDateTime.toLocalTime();
        return  localTime;
    }
}
